﻿using System;
using System.Collections.Generic;
using System.Data;
using IBM.Data.DB2;

using BizElements.Core;
using BizElements.Core.ProviderComponents;

namespace BizElements.Core.DB2
{
    /// <summary>Provides components for DB2 databases.</summary>
    sealed class DB2ComponentProvider : IDbmsComponentProvider
    {
        private static readonly Dictionary<Type, object> Components = CreateComponents();

        private static Dictionary<Type, object> CreateComponents()
        {
            Dictionary<Type, object> components = new Dictionary<Type, object>();

            //// All implementations are stateless, ie. have no fields, and are thread safe.
            //// Single instances serve all threads and clients.
            components[typeof(IDbCommandBuilder)] = new BizElements.Core.DB2.DB2CommandBuilder();
            components[typeof(IDataAdapterBuilder)] = new DB2DataAdapterBuilder();
            components[typeof(IParameterRenderer)] = new DB2ParameterRenderer();
            components[typeof(IFunctionRenderer)] = GenericDbmsComponents.NewFunctionRenderer();
            components[typeof(IAggregateFunctionRenderer)] = GenericDbmsComponents.NewAggregateFunctionRenderer();
            // In DB2 column and tables names must be written using exactly same identifiers as in sys tables. If they contains special chars then they are surrounded by quotes.
            components[typeof(IColumnRenderer)] = GenericDbmsComponents.NewColumnRenderer();
            components[typeof(ITableRenderer)] = GenericDbmsComponents.NewTableRenderer();
            components[typeof(IContainsPredicateRenderer)] = GenericDbmsComponents.NewContainsPredicateRenderer();
            components[typeof(ILikePredicateRenderer)] = GenericDbmsComponents.NewLikePredicateRenderer();
            components[typeof(IFromClauseRenderer)] = GenericDbmsComponents.NewFromClauseRenderer();
            components[typeof(IInserter)] = new DB2Inserter();
            components[typeof(ISelectRenderer)] = new DB2SelectRenderer();
            components[typeof(IUpdater)] = GenericDbmsComponents.NewUpdater();
            components[typeof(IDeleteRenderer)] = GenericDbmsComponents.NewDeleteRenderer();
            components[typeof(IHierarchicalQueryExecutor)] = GenericDbmsComponents.NewHierarchicalQueryExecutor();
            // No bulk saver.
            components[typeof(IConnectionProviderBuilder)] = new DB2ConnectionProviderBuilder();

            return components;
        }

        public T GetComponent<T>()
        {
            object component;
            bool exists = Components.TryGetValue(typeof(T), out component);
            if (exists && component != null)
                return (T)component;
            else
                return default(T);
        }
    }
}
